<?php

namespace app\service;

use app\exception\ErrnoPlus;
use app\model\VirtualDeviceModel;
use share\exception\ApiException;
use share\exception\Errno;
use share\service\BaseModelService;
use share\service\IdMakerService;
use share\service\UserBaseService;
use share\utils\Helper;

class VirtualDeviceService extends BaseModelService
{
    public static function getModel()
    {
        return new VirtualDeviceModel();
    }

    public static function getAllByUser($params)
    {
        $base = self::getAllByFilter([
            'uid' => $params['uid'],
        ]);
        if (!$base) {
            return [];
        }
        $user = UserBaseService::getBase($params['uid']);   
        $ids = array_column($base, 'id');
        $details = VirtualDeviceDetailService::getAllByUserDevice($params['uid'], $ids);
        $formatBase = Helper::arrayListUnderscoreToCamelKey($base);
        $formatDetails = Helper::arrayListUnderscoreToCamelKey($details);
        $res = [];
        foreach ($formatBase as &$item) {
            $id = $item['id'];
            $item['user_id'] = $user['user_id'];
            $children = Helper::filter($formatDetails, ['virtualDeviceId' => $id]);
            foreach ($children as &$child) {
                $child['userId'] = $user['user_id'];
            }
            $item['items'] = $children;
            $res[] = $item;
        }
        return $res;
    }

    public static function addDeviceInfo($params)
    {
        $tn = time();
        $uid = $params['uid'];
        $name = $params['name'];
        $exist = self::getByFilter(['uid' => $uid, 'name' => $name]);
        if ($exist) {
            throw new ApiException("already has device named '{$name}'", ErrnoPlus::INVALID_PARAM);
        }
        $id = IdMakerService::make(IdMakerService::NAME_OF_VIRTUAL_DEVICE);

        self::add([
            'id' => $id,
            'name' => $name,
            'uid' => $uid,
        ]);
        $inputDetails = [];
        foreach ($params['items'] as $item) {
            $inputDetails[] = [
                'main_id' => $item['mainId'],
                'sub_id' => $item['subId'],
                'virtual_device_id' => $id,
                'uid' => $uid,
                'firsttime' => $tn,
                'modifytime' => $tn,
            ];
        }
        if (count($inputDetails) > 0) {
            VirtualDeviceDetailService::addBulk($inputDetails);
        }
    }

    public static function updateDeviceInfo($params)
    {
        $tn = time();
        $id = $params['id'];
        $base = self::getBase($id);
        if(empty($base)){
            throw new ApiException("virtualDevice of id:{$id} not exists!", ErrnoPlus::COMMON_INVALID_INPUT);
        }
        $uid = $params['uid'];
        $name = $params['name'];
        if ($base['uid'] != $uid) {
            throw new ApiException("no access to change virtualDevice", Errno::COMMON_INVALID_INPUT);
        }
        if ($base['name'] != $name) {

            $exist = self::getByFilter(['uid' => $uid, 'name' => $name]);
            if ($exist) {
                throw new ApiException("already has another device named '{$name}'", ErrnoPlus::INVALID_PARAM);
            }
            self::update($id, [
                'name' => $name,
            ]);
        }
        $details = VirtualDeviceDetailService::getAllByUserMainDevice($uid, $id);
        $inputDetails = [];
        foreach ($params['items'] as $item) {
            $inputDetails[] = [
                'main_id' => $item['mainId'],
                'sub_id' => $item['subId'],
            ];
        }
        $existsDetails = [];
        foreach ($details as $item) {
            $existsDetails[] = [
                'main_id' => $item['main_id'],
                'sub_id' => $item['sub_id'],
            ];
        }

        // 子设备有变动
        if (md5(json_encode($inputDetails)) !== md5(json_encode($existsDetails))) {
            foreach ($inputDetails as &$item) {
                $item['virtual_device_id'] = $id;
                $item['uid'] = $uid;
                $item['firsttime'] = $tn;
                $item['modifytime'] = $tn;
            }
            VirtualDeviceDetailService::delByFilter([
                'virtual_device_id' => $id,
                'uid' => $uid,
            ]);
            VirtualDeviceDetailService::addBulk($inputDetails);
        }
    }

    public static function setDeviceInfo($params)
    {
        if ($params['id'] == 0) { //新增
            return self::addDeviceInfo($params);
        } else {
            return self::updateDeviceInfo($params);
        }
    }

    /**
     * 删除设备
     */
    public static function delDevice($params)
    {
        VirtualDeviceDetailService::delByFilter([
            'id' => $params['id'],
            'virtual_device_id' => $params['uid'],
        ]);
        self::delByFilter([
            'id' => $params['id'],
            'uid' => $params['uid'],
        ]);
        return;
    }

    /**
     * 删除子设备 取消/删除分享
     */
    public static function delSubDevice($uid, $shareId, $mainId, $subIds)
    {
        if (count($subIds) < 1) {
            return;
        }
        $shareUser = UserBaseService::getByUserId($shareId);
        if(empty($shareUser)){
            throw new ApiException("share user not exists. user_id:{$shareId} ",ErrnoPlus::COMMON_INVALID_INPUT);
        }
        $filter = [
            'uid' => $shareUser['id'],
            'main_id' => $mainId,
            'sub_id' => ['in', $subIds],
        ];
        $bindInfo = UserDeviceBindingService::getByFilter([
            'iot_id' => $mainId,
            'uid' => $uid,
        ]);
        if (empty($bindInfo)) {
            throw new ApiException("not found main device by iot_id:{$mainId} of user:{$uid}",ErrnoPlus::COMMON_INVALID_INPUT);
        }
        VirtualDeviceDetailService::delByFilter($filter);
        return;
    }

    /**
     * 主设备解绑 
     */
    public static function delMainDevice($iotId, $uid = null)
    {
        $filter = [
            'main_id' => $iotId,
        ];
        if ($uid) {
            $filter['uid'] = $uid;
        }
        VirtualDeviceDetailService::delByFilter($filter);
        return;
    }
}
